package com.onenine.chat.conversation;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.onenine.app.R;
import com.onenine.app.utils.CHelper;
import com.onenine.app.utils.GlideUtils;
import com.onenine.app.utils.RoleResLoader;
import com.onenine.chat.commons.IConversation;
import com.onenine.chat.commons.IMessage;
import com.onenine.chat.commons.ViewHolder;
import com.onenine.chat.model.LGroup;
import com.onenine.chat.model.LUser;
import com.onenine.chat.rongcloud.GroupCacheMgr;
import com.onenine.chat.rongcloud.UserCacheMgr;
import com.onenine.chat.util.SimpleCommonUtils;
import com.onenine.common.util.ApUtils;
import com.onenine.common.util.TimeUtils;
import com.othershe.combinebitmap.listener.OnProgressListener;

import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

/**
 * 会话列表适配器
 *
 * @param <T>
 */
public class ConversationListAdapter<T extends IConversation> extends RecyclerView.Adapter {

    private List<T> items;
    private int itemLayoutId;
    private Class<? extends BaseDialogViewHolder> holderClass;
    private OnDialogClickListener<T> onDialogClickListener;
    private OnDialogViewClickListener<T> onDialogViewClickListener;
    private OnDialogLongClickListener<T> onLongItemClickListener;
    private OnDialogViewLongClickListener<T> onDialogViewLongClickListener;
    private OnDialogDeleteClickListener<T> onDialogDeleteClickListener;
    private ConversationListStyle dialogStyle;

    public ConversationListAdapter() {
        this(R.layout.layout_conversation_item, DialogViewHolder.class);
    }

    public ConversationListAdapter(@LayoutRes int itemLayoutId) {
        this(itemLayoutId, DialogViewHolder.class);
    }

    public ConversationListAdapter(@LayoutRes int itemLayoutId, Class<? extends BaseDialogViewHolder> holderClass) {
        this.itemLayoutId = itemLayoutId;
        this.holderClass = holderClass;
    }

    @Override
    public BaseDialogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(itemLayoutId, parent, false);
        //create view holder by reflation
        try {
            Constructor<? extends BaseDialogViewHolder> constructor = holderClass.getDeclaredConstructor(View.class);
            constructor.setAccessible(true);
            BaseDialogViewHolder baseDialogViewHolder = constructor.newInstance(v);
            if (baseDialogViewHolder instanceof DialogViewHolder) {
                ((DialogViewHolder) baseDialogViewHolder).setDialogStyle(dialogStyle);
            }
            return baseDialogViewHolder;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
        BaseDialogViewHolder holder = (BaseDialogViewHolder) viewHolder;
        holder.setOnDialogClickListener(onDialogClickListener);
        holder.setOnDialogViewClickListener(onDialogViewClickListener);
        holder.setOnLongItemClickListener(onLongItemClickListener);
        holder.setOnDialogViewLongClickListener(onDialogViewLongClickListener);
        holder.setOnDialogDeleteClickListener(onDialogDeleteClickListener);
        holder.onBind(items.get(position), position);
    }

    @Override
    public int getItemCount() {
        if (items == null) {
            return 0;
        }
        return items.size();
    }

    public void deleteById(long targetId) {
        for (int i = 0; i < items.size(); i++) {
            if (items.get(i).getTargetId().equals(targetId)) {
                items.remove(i);
                notifyItemRemoved(i);
            }
        }
    }

    public void delete(T t) {
        int index = items.indexOf(t);
        if (index >= 0) {
            items.remove(index);
            notifyItemRemoved(index);
        }
    }

    public boolean isEmpty() {
        return items.isEmpty();
    }

    public void clear() {
        if (items != null) {
            items.clear();
        }
        notifyDataSetChanged();
    }

    public void setItems(List<T> items) {
        this.items = items;
        notifyDataSetChanged();
    }

    public List<T> getItems() {
        if (items == null)
            return new ArrayList<>();
        return items;
    }

    public void addItems(List<T> newItems) {
        if (newItems != null) {
            if (items == null) {
                items = new ArrayList<>();
            }
            int curSize = items.size();
            items.addAll(newItems);
            notifyItemRangeInserted(curSize, items.size());
        }
    }

    public void addItem(T dialog) {
        items.add(dialog);
        notifyItemInserted(0);
    }

    public void addItem(int position, T dialog) {
        items.add(position, dialog);
        notifyItemInserted(position);
    }

    public void updateItem(int position, T item) {
        if (items == null) {
            items = new ArrayList<>();
        }
        items.set(position, item);
        notifyItemChanged(position);
    }

    public void updateItemById(T item) {
        if (items == null) {
            items = new ArrayList<>();
        }
        for (int i = 0; i < items.size(); i++) {
            if (items.get(i).getTargetId().equals(item.getTargetId())) {
                items.set(i, item);
                notifyItemChanged(i);
                break;
            }
        }
    }

    public boolean updateDialogWithMessage(long id, IMessage message) {
        boolean dialogExist = false;
        for (int i = 0; i < items.size(); i++) {
            if (items.get(i).getTargetId().equals(id)) {
                items.get(i).setLastMessage(message);
                notifyItemChanged(i);
                if (i != 0) {
                    Collections.swap(items, i, 0);
                    notifyItemMoved(i, 0);
                }
                dialogExist = true;
                break;
            }
        }
        return dialogExist;
    }

    public OnDialogClickListener getOnDialogClickListener() {
        return onDialogClickListener;
    }

    public void setOnDialogClickListener(OnDialogClickListener<T> onDialogClickListener) {
        this.onDialogClickListener = onDialogClickListener;
    }

    public OnDialogViewClickListener getOnDialogViewClickListener() {
        return onDialogViewClickListener;
    }

    public void setOnDialogViewClickListener(OnDialogViewClickListener<T> clickListener) {
        this.onDialogViewClickListener = clickListener;
    }

    public OnDialogLongClickListener getOnLongItemClickListener() {
        return onLongItemClickListener;
    }

    public void setOnDialogLongClickListener(OnDialogLongClickListener<T> onLongItemClickListener) {
        this.onLongItemClickListener = onLongItemClickListener;
    }

    public OnDialogViewLongClickListener<T> getOnDialogViewLongClickListener() {
        return onDialogViewLongClickListener;
    }

    public void setOnDialogViewLongClickListener(OnDialogViewLongClickListener<T> clickListener) {
        this.onDialogViewLongClickListener = clickListener;
    }

    public void setOnDialogDeleteClickListener(OnDialogDeleteClickListener<T> onDialogDeleteClickListener) {
        this.onDialogDeleteClickListener = onDialogDeleteClickListener;
    }

    //TODO ability to set style programmatically
    void setStyle(ConversationListStyle dialogStyle) {
        this.dialogStyle = dialogStyle;
    }

    public interface OnDialogClickListener<DIALOG extends IConversation> {
        void onDialogClick(DIALOG dialog);
    }

    public interface OnDialogViewClickListener<DIALOG extends IConversation> {
        void onDialogViewClick(View view, DIALOG dialog);
    }

    public interface OnDialogLongClickListener<DIALOG extends IConversation> {
        void onDialogLongClick(DIALOG dialog);
    }

    public interface OnDialogViewLongClickListener<DIALOG extends IConversation> {
        void onDialogViewLongClick(View view, DIALOG dialog);
    }

    public interface OnDialogDeleteClickListener<DIALOG extends IConversation> {
        void onDialogDeleteClick(View view, DIALOG dialog);
    }

    public abstract static class BaseDialogViewHolder<DIALOG extends IConversation>
            extends ViewHolder<DIALOG> {

        protected OnDialogClickListener<DIALOG> onDialogClickListener;
        protected OnDialogLongClickListener<DIALOG> onLongItemClickListener;
        protected OnDialogViewClickListener<DIALOG> onDialogViewClickListener;
        protected OnDialogViewLongClickListener<DIALOG> onDialogViewLongClickListener;
        protected OnDialogDeleteClickListener<DIALOG> onDialogDeleteClickListener;

        public BaseDialogViewHolder(View itemView) {
            super(itemView);
        }

        protected void setOnDialogClickListener(OnDialogClickListener<DIALOG> onDialogClickListener) {
            this.onDialogClickListener = onDialogClickListener;
        }

        protected void setOnDialogViewClickListener(OnDialogViewClickListener<DIALOG> onDialogViewClickListener) {
            this.onDialogViewClickListener = onDialogViewClickListener;
        }

        protected void setOnLongItemClickListener(OnDialogLongClickListener<DIALOG> onLongItemClickListener) {
            this.onLongItemClickListener = onLongItemClickListener;
        }

        protected void setOnDialogViewLongClickListener(OnDialogViewLongClickListener<DIALOG> onDialogViewLongClickListener) {
            this.onDialogViewLongClickListener = onDialogViewLongClickListener;
        }

        protected void setOnDialogDeleteClickListener(OnDialogDeleteClickListener<DIALOG> onDialogDeleteClickListener) {
            this.onDialogDeleteClickListener = onDialogDeleteClickListener;
        }
    }

    public static class DialogViewHolder<DIALOG extends IConversation> extends BaseDialogViewHolder<DIALOG> {
        protected ConversationListStyle dialogStyle;
        protected ViewGroup container;
        protected TextView tvName;
        protected TextView tvDate;
        protected ImageView ivAvatar;
        protected TextView tvLastMessage;
        protected TextView tvBubble;
        protected Button btnDel;
        protected ImageView ivNoDisturb;
        private int mAvatarSize, mBubbleCommonSize, mBubbleNoDisturbSize;

        public DialogViewHolder(View itemView) {
            super(itemView);
            container = itemView.findViewById(R.id.dialogContainer);
            tvName = itemView.findViewById(R.id.conversationTitle);
            tvDate = itemView.findViewById(R.id.dialogDate);
            tvLastMessage = itemView.findViewById(R.id.dialogLastMessage);
            tvBubble = itemView.findViewById(R.id.dialogUnreadBubble);
            ivAvatar = itemView.findViewById(R.id.dialogAvatar);
            btnDel = itemView.findViewById(R.id.btn_delete);
            ivNoDisturb = itemView.findViewById(R.id.iv_no_disturb);
            Resources resources = ApUtils.getApp().getResources();
            mAvatarSize = resources.getDimensionPixelSize(R.dimen.dialog_avatar_width);
            mBubbleCommonSize = resources.getDimensionPixelSize(R.dimen.bubble_common_size);
            mBubbleNoDisturbSize = resources.getDimensionPixelSize(R.dimen.bubble_no_disturb_size);
        }

        private void applyStyle() {
            if (dialogStyle != null) {
                //Texts
                if (tvName != null) {
                    tvName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogTitleTextSize());
                }

                if (tvLastMessage != null) {
                    tvLastMessage.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogMessageTextSize());
                }

                if (tvDate != null) {
                    tvDate.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogDateSize());
                }

                //Avatar
                if (ivAvatar != null) {
                    ivAvatar.getLayoutParams().width = dialogStyle.getDialogAvatarWidth();
                    ivAvatar.getLayoutParams().height = dialogStyle.getDialogAvatarHeight();
                }

                //Unread bubble
                if (tvBubble != null) {
//                    GradientDrawable bgShape = (GradientDrawable) tvBubble.getBackground();
//                    bgShape.setColor(dialogStyle.getDialogUnreadBubbleBackgroundColor());
                    tvBubble.setVisibility(dialogStyle.isDialogDividerEnabled() ? VISIBLE : GONE);
                    tvBubble.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogUnreadBubbleTextSize());
                    tvBubble.setTextColor(dialogStyle.getDialogUnreadBubbleTextColor());
                    tvBubble.setTypeface(tvBubble.getTypeface(), dialogStyle.getDialogUnreadBubbleTextStyle());
                }
            }
        }


        private void applyDefaultStyle() {
            if (dialogStyle != null) {

                if (tvName != null) {
                    tvName.setTextColor(dialogStyle.getDialogTitleTextColor());
                    tvName.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogTitleTextStyle());
                }

                if (tvDate != null) {
                    tvDate.setTextColor(dialogStyle.getDialogDateColor());
                    tvDate.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogDateStyle());
                }

                if (tvLastMessage != null) {
                    tvLastMessage.setTextColor(dialogStyle.getDialogMessageTextColor());
                    tvLastMessage.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogMessageTextStyle());
                }
            }
        }

        private void applyUnreadStyle() {
            if (dialogStyle != null) {

                if (tvName != null) {
                    tvName.setTextColor(dialogStyle.getDialogUnreadTitleTextColor());
                    tvName.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadTitleTextStyle());
                }

                if (tvDate != null) {
                    tvDate.setTextColor(dialogStyle.getDialogUnreadDateColor());
                    tvDate.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadDateStyle());
                }

                if (tvLastMessage != null) {
                    tvLastMessage.setTextColor(dialogStyle.getDialogUnreadMessageTextColor());
                    tvLastMessage.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadMessageTextStyle());
                }
            }
        }

        @Override
        public void onBind(final DIALOG dialog, final int position) {
            if (dialog.getUnreadCount() > 0) {
                applyUnreadStyle();
            } else {
                applyDefaultStyle();
            }
            bindBubbleCount(dialog.getUnreadCount(), false);
            bindTargetInfo(dialog);
            setLastMessage(dialog.getLastMessage()
                    .getMessageType(), dialog.getLastMessage().getText());
            //设置会话时间，格式化
            tvDate.setText(TimeUtils.convertWXTimeStr(dialog.getTimestamp()));
            btnDel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onDialogDeleteClickListener != null) {
                        onDialogDeleteClickListener.onDialogDeleteClick(btnDel, dialog);
                    }
                }
            });
            container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (onDialogClickListener != null) {
                        onDialogClickListener.onDialogClick(dialog);
                    }
                    if (onDialogViewClickListener != null) {
                        onDialogViewClickListener.onDialogViewClick(view, dialog);
                    }
                }
            });

            container.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    if (onLongItemClickListener != null) {
                        onLongItemClickListener.onDialogLongClick(dialog);
                    }
                    if (onDialogViewLongClickListener != null) {
                        onDialogViewLongClickListener.onDialogViewLongClick(view, dialog);
                    }
                    return onLongItemClickListener != null || onDialogViewLongClickListener != null;
                }
            });
        }

        /**
         * 设置最新一条消息
         *
         * @param messageType
         * @param text
         */
        private void setLastMessage(IMessage.MessageType messageType, String text) {
            switch (messageType) {
                case SEND_IMAGE:
                case RECEIVE_IMAGE:
                    tvLastMessage.setText("[图片]");
                    break;
                case SEND_VOICE:
                case RECEIVE_VOICE:
                    tvLastMessage.setText("[语音]");
                    break;
                case SEND_VIDEO:
                case RECEIVE_VIDEO:
                    tvLastMessage.setText("[视频]");
                    break;
                default:
                    SimpleCommonUtils.spannableEmoticonFilter(tvLastMessage, text);
                    break;
            }
        }

        /**
         * 设置气泡数量
         *
         * @param count
         */
        private void bindBubbleCount(int count, boolean isNoDisturb) {
            ViewGroup.LayoutParams lp = tvBubble.getLayoutParams();
            tvBubble.setVisibility(count > 0 ? View.VISIBLE : View.GONE);
            ivNoDisturb.setVisibility(isNoDisturb ? View.VISIBLE : View.GONE);
            if (isNoDisturb) {
                //免打扰
                tvBubble.setText("");
                lp.width = mBubbleNoDisturbSize;
                lp.height = mBubbleNoDisturbSize;
            } else {
                //带数字
                tvBubble.setBackgroundResource(RoleResLoader
                        .getRoleDrawableResourceId(RoleResLoader.DynamicResName.CIRCLE_POINT_BUBBLE));
                tvBubble.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogUnreadBubbleTextSize());
                lp.width = mBubbleCommonSize;
                lp.height = mBubbleCommonSize;
                if (count > 99) {
                    tvBubble.setTextSize(TypedValue.COMPLEX_UNIT_PX, dialogStyle.getDialogUnreadBubbleTextSize() / 1.5f);
                    tvBubble.setText("99+");
                } else {
                    tvBubble.setText(count + "");
                }
            }
        }

        /**
         * 设置目标信息
         *
         * @param dialog
         */
        private void bindTargetInfo(final DIALOG dialog) {
            switch (dialog.getConversationType()) {
                case PRIVATE:
                    UserCacheMgr.getInstance().getUserAsync(dialog.getTargetId(), new UserCacheMgr.OnUserCallback() {
                        @Override
                        public void callback(LUser user) {
                            dialog.setConversationTitle(user.getNickName());
                            dialog.setPortraitUrl(user.getPhoto());
                            tvName.setText(user.getNickName());
                            GlideUtils.loadCircleAvatar(ApUtils.getApp(), ivAvatar
                                    , CHelper.getOssThumbImageUrl(dialog.getPortraitUrl(), mAvatarSize));
                        }
                    });
                    break;
                case GROUP:
                    GroupCacheMgr.getInstance().getGroupAsync(dialog.getTargetId(), new GroupCacheMgr.OnGroupCallback() {
                        @Override
                        public void callback(final LGroup group) {
                            if (group == null) {
                                return;
                            }
                            if (group.getNoDisturb() > 0) {
                                //免打扰状态
                                bindBubbleCount(dialog.getUnreadCount(), true);
                            }
                            if (group.getPhotoReference() != null) {
                                ivAvatar.setImageBitmap(group.getPhotoReference().get());
                            }
                            dialog.setConversationTitle(group.getGroupName());
                            dialog.setPortraitUrl(group.getGroupPhoto());
                            tvName.setText(group.getGroupName());
                            if (group.getGroupPhoto() == null) {
                                return;
                            }
                            GlideUtils.loadWechatBitmap(ApUtils.getApp()
                                    , ivAvatar, new OnProgressListener() {
                                        @Override
                                        public void onStart() {

                                        }

                                        @Override
                                        public void onComplete(Bitmap bitmap) {
                                            group.setPhotoReference(new SoftReference<>(bitmap));
                                        }
                                    }, group.getGroupPhoto().split(","));
                        }
                    });
                    break;
                default:
                    tvName.setText(dialog.getConversationTitle());
                    GlideUtils.loadCircleAvatar(ApUtils.getApp(), ivAvatar
                            , CHelper.getOssThumbImageUrl(dialog.getPortraitUrl(), mAvatarSize));
                    break;
            }
        }

        protected void setDialogStyle(ConversationListStyle dialogStyle) {
            this.dialogStyle = dialogStyle;
            applyStyle();
        }
    }

}
